package com.ld.admin.service.outdatabase;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.poi.ss.usermodel.Workbook;
import org.jsoup.Connection.Method;
import org.jsoup.Connection.Response;
import org.jsoup.Jsoup;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STJc;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.data.DocxRenderData;
import com.deepoove.poi.data.MiniTableRenderData;
import com.deepoove.poi.data.RowRenderData;
import com.deepoove.poi.data.TextRenderData;
import com.deepoove.poi.data.style.Style;
import com.deepoove.poi.data.style.TableStyle;
import com.ld.admin.model.system.outdatabase.OutDatabaseExcelModel;
import com.ld.admin.model.system.outdatabase.OutDatabaseTableModel;
import com.ld.admin.model.system.outdatabase.OutDatabaseTablePageModel;
import com.ld.admin.model.system.outdatabase.OutType;
import com.ld.admin.service.codegen.CodegenService;
import com.ld.admin.utils.ExcelStyleUtil;
import com.ld.admin.utils.ExportUtil;
import com.ld.shieldsb.common.core.collections.ListUtils;
import com.ld.shieldsb.common.core.io.IOUtils;
import com.ld.shieldsb.common.core.util.BeetlUtil;
import com.ld.shieldsb.common.core.util.JsoupUtil;
import com.ld.shieldsb.common.core.util.StringUtils;
import com.ld.shieldsb.common.core.util.properties.ConfigFile;
import com.ld.shieldsb.common.core.util.properties.ConfigFileBuilder;
import com.ld.shieldsb.common.web.BasicService;
import com.ld.shieldsb.db.model.DBSetInfo;
import com.ld.shieldsb.db.model.DBTableColumnModel;
import com.ld.shieldsb.db.model.DBTableModel;
import com.ld.shieldsb.db.service.DBTabelService;
import com.ld.shieldsb.pdf.PdfDocumentGenerator;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;

/**
 * @ClassName OutDatabaseService
 * @Description 导出数据库字段Service {word和Excel两个方法}
 * @Author 林昊
 * @Date 2019/8/6 15:10
 * @ModifyDate 2019/8/6 15:10
 * @Version 1.0
 */
@Service
public class OutDatabaseService extends BasicService {
    @Autowired
    public CodegenService codegenService;
    private Style headTextStyle = new Style();// 标题栏文本样式
    private TableStyle headStyle = new TableStyle();// 标题栏样式
    private TableStyle bodyStyle = new TableStyle();// 内容区样式
    private Style bodyTextStyle = new Style();// 标题栏文本样式
    private TableStyle rowStyle = new TableStyle();// 行样式

    public ConfigFile config = ConfigFileBuilder.build("codegen_outfile.properties"); // 配置文件

    public final static String WORD_SUFFIX = "database.word.suffix"; // word后缀
    public final static String WORD_HEAD_BGCOLOR = "database.word.head.bgcolor"; // 表头背景色
    public final static String WORD_HEAD_ALIGN = "database.word.head.align"; // 表头居中情况
    public final static String WORD_HEAD_FONTSIZE = "database.word.head.fontsize"; // 表头字体大小
    public final static String WORD_HEAD_FONTFAMILY = "database.word.head.fontfamily"; // 表头字体类型
    public final static String WORD_BODY_BGCOLOR = "database.word.body.bgcolor"; // 内容背景色
    public final static String WORD_BODY_FONTSIZE = "database.word.body.fontsize"; // 内容字体大小
    public final static String WORD_BODY_FONTFAMILY = "database.word.body.fontfamily"; // 内容字体类型

    public final static String EXCEL_SUFFIX = "database.excel.suffix"; // excel后缀

    public final static String PDF_REMOTEURL = "database.pdf.remoteUrl"; // 远程下载地址

    /**
     * 下载文件
     * 
     * @Title outFile
     * @author 吕凯
     * @date 2019年8月20日 下午5:48:24
     * @param tableNames
     *            表名数组
     * @param dbConnId
     *            链接标识id
     * @param type
     *            输出类型
     * @return
     * @throws IOException
     *             ResponseEntity<FileSystemResource>
     */
    public ResponseEntity<FileSystemResource> outFile(String[] tableNames, Long dbConnId, OutType type) throws IOException {
        DBSetInfo dbSetInfo = codegenService.getDbSetInfo(dbConnId);
        String dbName = dbSetInfo.getDbName();
        DBTabelService service = DBTabelService.getInstance(dbSetInfo);
        // 查询到所有的表
        List<DBTableModel> dbList = service.getTables("");

        List<DBTableModel> tabledata = new ArrayList<>();// 建立容器来装数据
        for (DBTableModel dbTableModel : dbList) {// 遍历全部表
            for (String tableName : tableNames) {// 遍历获取到的表
                if (tableName.equals(dbTableModel.getTableName())) {// 如果相同
                    tabledata.add(dbTableModel);
                }
            }
        }
        tabledata.forEach(dbTableModels -> {
            // 根据名称查询列字段
            List<DBTableColumnModel> tablCols = service.getTableColumn(dbTableModels.getTableName());
            dbTableModels.setColumns(tablCols);

        });
        String fileNameSuffix = "数据库表结构"; // 文件名
        if (type == OutType.EXCEL) {
            outExcel(tabledata, dbName, fileNameSuffix);
        } else if (type == OutType.WORD) { //
            outWord(tabledata, dbName, fileNameSuffix);
        } else if (type == OutType.PDF) {
            exportPdf(tabledata, dbName, fileNameSuffix);
        }

        return null;
    }

    /**
     * 
     * 导出WORD到response流
     * 
     * @Title outExcel
     * @author 林昊
     * @date 2019年8月9日8:59
     * @param tabledata
     *            表结构数据
     * @param dbName
     *            数据库名
     * @param fileNameSuffix
     *            文件后缀
     * @return
     * @throws IOException
     *             ResponseEntity<FileSystemResource>
     */
    public ResponseEntity<FileSystemResource> outWord(List<DBTableModel> tabledata, String dbName, String fileNameSuffix)
            throws IOException {
        String suffix = config.getString(WORD_SUFFIX, ".docx"); // 文件名后缀
        // 主模板：包含表格模板和标题 （一个标题和多个表模板组成）
        // 表格模板：选中的表名集合，里面每张表的都需要用这个模板来进行生成（表名+表注释+表信息）的内容

        try (// 标题：生成文件标题（例如：XXX数据库表结构）
                InputStream outDatabaseIn = IOUtils.readAsInputStream("templates/outdatabase/outDatabaseTemplate.docx");
                // 表格模板（单个表的内容，相当于同一个子模块，很多个表格模板相加才会组成主模板，表格模板的数量取决于选中的表名数量）
                InputStream tableTemplateIn = IOUtils.readAsInputStream("templates/outdatabase/outDatabaseTableTemplate.docx");) {

            // headTextStyle.setColor("ff0000");字体颜色
            // headTextStyle.setHighlightColor(STHighlightColor.Enum.forInt(2)); 字体背景

            // 表头数据处理
            String columnName = ExportUtil.getFiledExcelShowName(OutDatabaseExcelModel::getColumnName); // 字段名
            String columnType = ExportUtil.getFiledExcelShowName(OutDatabaseExcelModel::getColumnType); // 字段类型
            String nullable = ExportUtil.getFiledExcelShowName(OutDatabaseExcelModel::getNullable); // 是否允许为空
            String defaultValue = ExportUtil.getFiledExcelShowName(OutDatabaseExcelModel::getDefaultValue);
            String remarks = ExportUtil.getFiledExcelShowName(OutDatabaseExcelModel::getRemarks); // 备注
            RowRenderData header = RowRenderData.build(new TextRenderData(columnName, headTextStyle), new TextRenderData(columnType),
                    new TextRenderData(nullable, headTextStyle), new TextRenderData(defaultValue, headTextStyle),
                    new TextRenderData(remarks, headTextStyle));

            // 表头样式处理
            if (StringUtils.isNotBlank(config.getString(WORD_HEAD_FONTSIZE))) { // 字号
                headTextStyle.setFontSize(config.getInt(WORD_HEAD_FONTSIZE, 11));
            }
            if (StringUtils.isNotBlank(config.getString(WORD_HEAD_FONTFAMILY))) { // 字体
                headTextStyle.setFontFamily(config.getString(WORD_HEAD_FONTSIZE));
            }
            // 设置字段名居中
            headStyle.setAlign(STJc.Enum.forString(config.getString(WORD_HEAD_ALIGN, "left")));
            headStyle.setBackgroundColor(config.getString(WORD_HEAD_BGCOLOR, "cccccc"));// 标题背景
            header.setRowStyle(headStyle);// 给表头添加字段名居中

            // new出 word 的整个页面
            OutDatabaseTablePageModel outDatabaseTablePage = new OutDatabaseTablePageModel();
            outDatabaseTablePage.setName(dbName);// 数据库名称
            // 对表进行分模块，每个模块是一张表，在同一个word里面
            List<OutDatabaseTableModel> tables = new ArrayList<>();

            // 表内容样式处理
            if (StringUtils.isNotBlank(config.getString(WORD_BODY_FONTSIZE))) { // 字号
                bodyTextStyle.setFontSize(config.getInt(WORD_BODY_FONTSIZE, 11));
            }
            if (StringUtils.isNotBlank(config.getString(WORD_BODY_FONTFAMILY))) { // 字体
                bodyTextStyle.setFontFamily(config.getString(WORD_BODY_FONTFAMILY));
            }
            tabledata.forEach(dbTableModels -> { // 1、循环表
                // 这里是建议一张表
                OutDatabaseTableModel outtable = new OutDatabaseTableModel();
                // 根据名称查询列字段
                List<DBTableColumnModel> tablCols = dbTableModels.getColumns();
                // 建立数组来存储表的每行数据
                List<RowRenderData> rowRenderData = new ArrayList<>();
                tablCols.forEach(columnModel -> { // 2、循环表字段
                    RowRenderData row = RowRenderData.build(new TextRenderData(columnModel.getColumnName(), bodyTextStyle), // 添加行名称
                            new TextRenderData(columnModel.getColumnType(), bodyTextStyle), // 添加行数据类型
                            new TextRenderData(columnModel.getNullable().toString(), bodyTextStyle), // 字段是否为空
                            new TextRenderData((String) columnModel.getDefaultValue(), bodyTextStyle), // 字段默认值
                            new TextRenderData(columnModel.getRemarks(), bodyTextStyle));// 字段名注释
                    row.setRowStyle(rowStyle);
                    rowRenderData.add(row);
                });
                // 添加表每行数据
                MiniTableRenderData miniTableRenderData = new MiniTableRenderData(header, rowRenderData, MiniTableRenderData.WIDTH_A4_FULL);

                bodyStyle.setBackgroundColor(config.getString(WORD_BODY_BGCOLOR, "cccccc"));// 数据背景
                miniTableRenderData.setStyle(bodyStyle);// 添加样式

                outtable.setTableData(miniTableRenderData);
                // 添加注释和表名称
                outtable.setTableName(dbTableModels.getTableName());// 表名
                outtable.setTableComments(dbTableModels.getTableComments()); // 注释
                // 添加到集合中
                tables.add(outtable);

            });
            DocxRenderData data = new DocxRenderData(tableTemplateIn, tables);
            outDatabaseTablePage.setTableInfos(data);
            // 进行渲染
            XWPFTemplate template = XWPFTemplate.compile(outDatabaseIn).render(outDatabaseTablePage);
            // 新建临时文件 临时文件名称 + 数据库名（对名称进行utf转码） +“数据库表结构。docx”
            String fileName = dbName + fileNameSuffix + suffix;
            initResponseOutputStream(fileName);
            template.write(response.getOutputStream());
            template.close();
        }

        return null;
    }

    /**
     * 
     * 导出EXCEL到response流
     * 
     * @Title outExcel
     * @author 付信豪
     * @date 2019年8月9日 8:55
     * @param tabledata
     *            表结构数据
     * @param dbName
     *            数据库名
     * @param fileNameSuffix
     *            文件后缀
     * @return
     * @throws IOException
     *             ResponseEntity<FileSystemResource>
     */
    public ResponseEntity<FileSystemResource> outExcel(List<DBTableModel> tabledata, String dbName, String fileNameSuffix)
            throws IOException {
        String suffix = config.getString(EXCEL_SUFFIX, ".docx"); // 文件名后缀
        // 建立存放表结构 execl数据
        List<OutDatabaseExcelModel> execlList = new ArrayList<>();
        // 判断获取的数组是否为空
        if (ListUtils.isNotEmpty(tabledata)) {
            // 循环 通过表名 获取表结构
            tabledata.forEach(dbTableModels -> {
                String TableComments = dbTableModels.getTableComments();
                List<DBTableColumnModel> tablCols = dbTableModels.getColumns();
                for (DBTableColumnModel tablCol : tablCols) {
                    OutDatabaseExcelModel excelModel = new OutDatabaseExcelModel();
                    excelModel.setTableName(tablCol.getTableName()); // 表名
                    excelModel.setTableComments(TableComments); // 表注释
                    excelModel.setColumnName(tablCol.getColumnName());// 字段名
                    excelModel.setColumnType(tablCol.getColumnType());// 字段数据类型
                    excelModel.setDefaultValue(tablCol.getDefaultValue());// 字段默认值
                    excelModel.setNullable(tablCol.getNullable());// 字段是否为空
                    excelModel.setRemarks(tablCol.getRemarks());// 字段注释
                    execlList.add(excelModel);
                }
            });
            // 初始化
            ExportParams exportParams = new ExportParams(dbName + "库", "表结构", ExcelType.HSSF);
            // 设置单元格样式
            exportParams.setStyle(ExcelStyleUtil.class);
            // 创建工作簿 导入数据模型
            Workbook workbook = ExcelExportUtil.exportExcel(exportParams, OutDatabaseExcelModel.class, execlList);
            String fileName = dbName + fileNameSuffix + suffix;
            initResponseOutputStream(fileName);
            workbook.write(response.getOutputStream());
            workbook.close();
            // 返回下载地址
            return null;
        }
        return null;
    }

    /**
     * 导出PDF到response流
     * 
     * @Title exportPdf
     * @author 吕凯
     * @date 2019年10月16日 下午3:32:39
     * @param tabledata
     * @param dbName
     * @param fileNameSuffix
     * @return
     * @throws IOException
     *             ResponseEntity<FileSystemResource>
     */
    public ResponseEntity<FileSystemResource> exportPdf(List<DBTableModel> tabledata, String dbName, String fileNameSuffix)
            throws IOException {
        String suffix = ".pdf"; // 文件名后缀
        String template = "outdatabase/exportDatabasePdf.html"; // 模板路径，相对于class目录的templates目录的相对路径
        String remoteUrl = config.getString(PDF_REMOTEURL); // 文件名后缀
        String fileName = dbName + fileNameSuffix + suffix;
        initResponseOutputStream(fileName);
        Map<String, Object> mapDataV = new HashMap<String, Object>();
        mapDataV.put("tables", tabledata);
        mapDataV.put("dbName", dbName);
        if (StringUtils.isNotEmpty(remoteUrl)) { // 调用远程的
            try {
                String htmlContent = BeetlUtil.render(template, mapDataV);
                Map<String, String> data = new HashMap<>();
                data.put("filename", fileName);
                data.put("html", htmlContent);
                // 注意使用post方法
                Response resultImageResponse = Jsoup.connect(remoteUrl).data(data).method(Method.POST).userAgent(JsoupUtil.USER_AGENT)
                        .ignoreContentType(true).execute();
                response.getOutputStream().write(resultImageResponse.bodyAsBytes());
            } catch (Exception e) {
                log.error("", e);
            }
        } else { // 本地导出
            // 导出类
            PdfDocumentGenerator pdfDocumentGenerator = new PdfDocumentGenerator();
            try {
                pdfDocumentGenerator.generate(template, mapDataV, response.getOutputStream());
            } catch (Exception e) {
                log.error("", e);
            }

        }
        return null;
    }

    /**
     * 初始化输出流
     * 
     * @Title initOutputStream
     * @author 吕凯
     * @date 2019年8月20日 下午1:43:48
     * @param fileName
     * @throws UnsupportedEncodingException
     *             void
     */
    private void initResponseOutputStream(String fileName) throws UnsupportedEncodingException {
        response.reset();
        response.setContentType("APPLICATION/OCTET-STREAM");
        response.addHeader("Cache-Control", "no-cache, no-store, must-revalidate");
        response.addHeader("Pragma", "no-cache");
        response.addHeader("Expires", "0");
        response.setHeader("Content-Disposition", "attachment; filename=\"" + new String(fileName.getBytes("GBK"), "iso-8859-1") + "\"");
    }
}